﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace QuailSeleniumManager
{
    /// <summary>
    /// Enumerates windows
    /// </summary>
    public class EnumWindows
    {
        /// <summary>
        /// Delegate for EnumChildWindows callback
        /// </summary>
        /// <param name="hWnd">handle of found window</param>
        /// <returns>true if the enumeration should continue</returns>
        public delegate bool EnumChildWindowsProc(IntPtr hWnd);

        /// <summary>
        /// Delegate for the EnumChildWindows method
        /// </summary>
        /// <param name="hWnd">Window handle</param>
        /// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
        /// <returns>True to continue enumerating, false to bail.</returns>
        private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

        /// <summary>
        /// Enumerates child windows
        /// </summary>
        /// <param name="callback">the callback to perform during the enumeration</param>
        /// <param name="parent">the parent of the windows</param>
        public static void EnumChildWindows(EnumChildWindowsProc callback, IntPtr parent)
        {
            GCHandle cbhandle = GCHandle.Alloc(callback);

            try
            {
                EnumChildWindows(parent, EnumChildWindow, GCHandle.ToIntPtr(cbhandle));
            }
            finally
            {
                if (cbhandle.IsAllocated)
                    cbhandle.Free();
            }
        }

        /// <summary>
        /// Returns a list of child windows
        /// </summary>
        /// <param name="parent">Parent of the windows to return</param>
        /// <returns>List of child windows</returns>
        public static List<IntPtr> GetChildWindows(IntPtr parent)
        {
            var result = new List<IntPtr>();
            EnumChildWindowsProc cb = hWnd =>
                                          {
                                              result.Add(hWnd);
                                              return true;
                                          };

            EnumChildWindows(cb, parent);

            return result;
        }

        [DllImport("user32")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);

        private static bool EnumChildWindow(IntPtr handle, IntPtr pointer)
        {
            GCHandle gch = GCHandle.FromIntPtr(pointer);
            var cb = gch.Target as EnumChildWindowsProc;

            if (cb == null)
            {
                throw new InvalidCastException("GCHandle Target could not be cast as EnumChildWindowsProc");
            }

            return cb(handle);
        }
    }
}
